package com.zking.web;

import com.zking.dao.domain.*;
import com.zking.service.ResourcesService;
import com.zking.service.SysRoleService;
import com.zking.service.UserService;
import com.zking.utils.RequestUtils;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.*;


@Controller
@RequestMapping(value = "/auth", name = "登陆控制器")
//@RequiresPermissions(value = {"auth", "auth:xxx"}, logical = Logical.OR)
//@RequiresRoles(value = {"ADMINISTATOR","USER", "SUPERADMINISTATOR"})
public class LoginController {

    @Autowired
    private UserService userService;

    @Autowired
    private SysRoleService roleService;

    @Autowired
    private ResourcesService resourcesService;

    @RequestMapping(value = "/login", method = RequestMethod.POST, name = "POST登陆")
    //@RequiresPermissions(value = {"auth:login"})
    public String submitLogin(String username, String password, HttpServletRequest request) {
        try {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            //获取当前用户的所有信息，包装Subject对象中
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isAuthenticated()) {
                subject.login(token);
                //没有操作的情况下，多少毫秒之后T出登陆
                //shiro会默认拿这个数除以1000.默认去掉小数。
                //不能设置为0
                //永久有效，设置为-1000以上都行
                //设置再登陆之后
                //默认是30分钟1800000毫秒
                subject.getSession().setTimeout(1000000);//毫秒为单位
                SysUser user = (SysUser) subject.getPrincipal();
                //记住密码
                token.setRememberMe(true);
            }

        } catch (DisabledAccountException e) {
            request.setAttribute("msg", "账户已被禁用");
            return "login";
        } catch (AuthenticationException e) {
            request.setAttribute("msg", "用户名或密码错误");
            return "login";
        }

        // 执行到这里说明用户已登录成功
        return "redirect:/auth/index";
    }


    @RequestMapping(value = "/toLogin", method = RequestMethod.GET, name = "GET登陆页面")
    public String loginPage() {
        return "login";
    }

   /* @RequiresAuthentication：表示当前Subject已经通过login 进行了身份验证；即 Subject. isAuthenticated() 返回 true

            • @RequiresUser：表示当前 Subject 已经身份验证或者通过记住我登录的。

            • @RequiresGuest：表示当前Subject没有身份验证或通过记住我登录过，即是游客身份。

            • @RequiresRoles(value={“admin”, “user”}, logical= Logical.AND)：表示当前 Subject 需要角色 admin 和user
• @RequiresPermissions (value={“user:a”, “user:b”}, logical= Logical.OR)：表示当前 Subject 需要权限 user:a 或
    user:b。

            • @RequiresPermissions (value={“user:a”, “user:b”}, logical= Logical.OR)：表示当前 Subject 需要权限 user:a 或
    user:b。*/

    @RequestMapping(value = "/index", method = RequestMethod.GET, name = "后台首页")
    public String loginSuccessMessage(HttpServletRequest request) {
        String username = "未登录";
        SysUser currentLoginUser = RequestUtils.currentLoginUser();

        if (currentLoginUser != null && StringUtils.isNotEmpty(currentLoginUser.getUserName())) {
            username = currentLoginUser.getUserName();
        } else {
            return "redirect:/auth/toLogin";
        }
        //查询所有用户
        List<SysUser> users = userService.findUsers();
        //查询每个用户对应的所有角色
        Map<SysUser, List<SysRole>> map = new TreeMap<SysUser, List<SysRole>>(
        new Comparator<SysUser>() {
            @Override
            public int compare(SysUser o1, SysUser o2) {
                return o1.getId().compareTo(o2.getId());
            }
        });
        for (SysUser user : users) {
            List<SysRole> roles = roleService.findRolesByUserId(user.getId());
            map.put(user, roles);
        }

        //查询所有角色
        List<SysRole> roles = userService.findRoles();
        request.setAttribute("username", username);
        request.setAttribute("map", map);
        request.setAttribute("roles", roles);
        return "index";
    }

    //被踢出后跳转的页面
    @RequestMapping(value = "/kickout", method = RequestMethod.GET, name = "登陆限制")
    public String kickOut() {
        return "kickout";
    }

    //@RequiresPermissions(value = {"auth:updateAuthority"})
    @RequestMapping(value = "/updateAuthority", name = "更新权限")
    public String updateAuthority(Model model) throws UnsupportedEncodingException, ClassNotFoundException {
        //获取本类的对象
        Class clas = LoginController.class;
        //获取包路径
        String packageName = clas.getPackage().getName().replaceAll("\\.","/");
        //获取类所在的绝对根路径
        String path = clas.getResource("/").getPath();
        path = URLDecoder.decode(path, "UTF-8");
        String filePath = path + packageName;
        //找到该类下的所有类文件
        File file = new File(filePath);
        File[] files = file.listFiles();

        List<SysResources> resources = new ArrayList<>();
        for (File file1 : files) {
            //获取类名
            String className = file1.getName().substring(0, file1.getName().lastIndexOf(".class"));
            //去掉内部类的情况
            if (className.indexOf("$") != -1) {
                //去掉内部类
                //className = className.substring(0, className.indexOf("$"));
                continue;
            }

            //获取类的反射
            Class clas2 = Class.forName(clas.getPackage().getName()+"."+className);
            //获取每个类的RequestMapping注解
            RequestMapping requestMapping = (RequestMapping) clas2.getAnnotation(RequestMapping.class);
            //设置得到的跟目录
            SysResources sr1 = new SysResources();
            sr1.setUserName(requestMapping.name());
            String controllerUrl = requestMapping.value()[0];
            //判断是不是以/开头
            controllerUrl = controllerUrl.startsWith("/")?controllerUrl:"/"+controllerUrl;
            sr1.setResUrl(controllerUrl);
            resources.add(sr1);
            //获取所有方法的请求
            Method[] methods = clas2.getDeclaredMethods();
            for (Method method : methods) {
                RequestMapping requestMapping2 = method.getAnnotation(RequestMapping.class);
                if (requestMapping2 != null) {
                    SysResources sr2 = new SysResources();
                    sr2.setUserName(requestMapping2.name());
                    String methodUrl = requestMapping2.value()[0];
                    //判断是不是以/开头
                    methodUrl = methodUrl.startsWith("/")?methodUrl:"/"+methodUrl;
                    sr2.setResUrl(sr1.getResUrl()+methodUrl);
                    resources.add(sr2);
                }
            }
        }
        //数据库查询的所有资源权限数据
        List<SysResources> resourcesAll = userService.findPermissions();

        List<SysResources> resourcesAdd = new ArrayList<>();
        //查找没有增加进去的资源权限
        for (SysResources resource : resources) {
            boolean flag = false;
            //一个一个去比较
            for (SysResources sysResources : resourcesAll) {
                if (resource.getResUrl().equals(sysResources.getResUrl())) {
                    flag = true;//已存在，不加入
                    break;
                }
            }
            if (!flag) {
                //没有进入if条件，证明不存在
                resourcesAdd.add(resource);
            }
        }
        int count = resourcesService.addResources(resourcesAdd);

        resourcesAll = userService.findPermissions();
        //System.out.println(resourcesAdd);
        model.addAttribute("resources", resourcesAll);
        model.addAttribute("count", count);
        return "synchroAuthority";
    }

    @RequestMapping(value = "/queryAllAuthority", name = "分配所有的权限")
    public String queryAllAuthority(Model model, SysRole sysRole) {
        List<SysResources> resources = userService.findPermissions();
        //查询所有的角色
        List<SysRole> roles = userService.findRoles();
        //根据角色的id查询对应的权限
        List<SysResources> resourcesRoles = userService.findPermissionsByRoleId(sysRole.getId());
        //匹配每一个是否有权限
        Map<SysResources, Object> map = new TreeMap<SysResources, Object>(
            new Comparator<SysResources>() {
            @Override
            public int compare(SysResources o1, SysResources o2) {
                return o1.getResUrl().compareTo(o2.getResUrl());
            }
        });
        for (SysResources resource : resources) {
            boolean flag = false;
            for (SysResources resourcesRole : resourcesRoles) {
                if (resource.getResUrl().equals(resourcesRole.getResUrl())) {
                    flag = true;
                    break;
                }
            }
            if (flag) {
                map.put(resource, 1);
            } else {
                map.put(resource, 0);
            }
        }

        model.addAttribute("roles", roles);
        model.addAttribute("sysRole", sysRole);
        model.addAttribute("resourcesMap", map);
        return "assignPermissions";
    }

    @RequestMapping(value = "/toReg", name = "去注册页面")
    public String toReg(){
        return "reg";
    }

    @RequestMapping(value = "/reg", name = "注册")
    public String reg(String username, String password){
        SysUser sysUser = new SysUser();
        sysUser.setUserName(username);
        sysUser.setPassWord(password);
        sysUser.setUserEnable(1);
        //加密类型
        String hashAlgorithmName = "SHA1";
        //需要加密的密码
        Object credentials = sysUser.getPassWord();
        //随机生成的盐值
        String saltStr = UUID.randomUUID().toString().replaceAll("\\-","");
        //用户名作为盐值，用户名是唯一，配上密码就是唯一的。
        Object salt = ByteSource.Util.bytes(saltStr);
        //Object salt = null;
        int hashIterations = 256;
        //生成一个新的密码
        Object newPwd = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
        //设置新密码到用户中
        sysUser.setPassWord(newPwd.toString());
        sysUser.setSalt(saltStr);
        //新增
        boolean result = userService.addUser(sysUser);

        return "login";
    }


    @RequestMapping(value = "/addAuthority", name = "增加权限")
    public String addAuthority(SysRoleResources roleResources, Integer has, String roleDesc){
        System.out.println(roleResources);
        if (has == 1) {
            //需要增加权限
            roleService.addAuthority(roleResources);
        } else {
            //需要删除权限
            roleService.deleteAuthority(roleResources);
        }
        return "redirect:/auth/queryAllAuthority?id="+roleResources.getRoleId()+"&roleDesc="+roleDesc;
    }


    @RequestMapping(value = "/lock", name = "解锁和锁定")
    public String lock(Integer userId, Integer userEnable){
        boolean result = userService.updateUserByLock(userId, userEnable);
        return "redirect:/auth/index";
    }

    @RequestMapping(value = "/giveRole", name = "赋予用户角色")
    public String giveRole(SysUserRole userRole, boolean checked) {
        if (checked) {
            //为true代表被选中

            boolean result = userService.addUserRole(userRole);
        } else {
            //否则去除权限
            boolean result = userService.deleteUserRole(userRole);
        }

        return "redirect:/auth/index";
    }


    /*@RequestMapping(value = "/toIndex", name = "首页测试")
    public String toIndex(){
        return "index";
    }*/


}
